/**
 * 
 */
package fr.utbm.gi.vi51.slizers.framework.agent;

import javax.vecmath.Point2i;

import fr.utbm.gi.vi51.slizers.framework.util.Vector2i;

/**
 * Abstract implementation of a situated object in an environment.
 *
 * @author Tarik Belabbas
 *
 */
public abstract class AbstractSituatedObject implements SituatedObject
{
	/**
	 * The position of the situated object.
	 */
	private final Point2i position = new Point2i();

	/**
	 * The direction of the situated object.
	 */
	private Direction direction = Direction.RIGHT;
	
	/**
	 * Default constructor.
	 * 
	 */
	public AbstractSituatedObject()
	{
		
	}
	
	/* (non-Javadoc)
	 * @see fr.utbm.gi.vi51.slizers.framework.environment.SituatedObject#getX()
	 */
	@Override
	public int getX()
	{
		return this.position.getX();
	}

	/* (non-Javadoc)
	 * @see fr.utbm.gi.vi51.slizers.framework.environment.SituatedObject#getY()
	 */
	@Override
	public int getY()
	{
		return this.position.getY();
	}

	/* (non-Javadoc)
	 * @see fr.utbm.gi.vi51.slizers.framework.environment.SituatedObject#getPosition()
	 */
	@Override
	public Point2i getPosition()
	{
		return this.position;
	}
	
	/**
	 * Sets the position.
	 * 
	 * @param _position the new position
	 */
	public void setPosition( Point2i _position )
	{
		this.position.set( _position );
	}
	
	/**
	 * Sets the position.
	 * 
	 * @param _x the new x-coordinate of the position
	 * @param _y the new y-coordinate of the position
	 */
	public void setPosition( int _x, int _y )
	{
		this.position.set( _x, _y );
	}

	/* (non-Javadoc)
	 * @see fr.utbm.gi.vi51.slizers.framework.environment.SituatedObject#getDirection()
	 */
	@Override
	public Direction getDirection()
	{
		return this.direction;
	}
	
	/**
	 * Sets the direction.
	 * 
	 * @param _direction the new direction
	 */
	public void setDirection( Direction _direction )
	{
		this.direction = _direction;
	}
	
	/**
	 * Sets the direction to its opposite.
	 */
	public void invertDirection()
	{
		this.direction = this.direction.opposite();
	}
	
	/**
	 * Moves the situated object.
	 * 
	 * @param _dx the real instant motion
	 * @param _dy the real instant motion
	 * @param _simulationDuration the time during which the motion is applied
	 * @param _environmentWidth the width of the world
	 * @param _environmentHeight the height of the world
	 * @return the real motion
	 */
	public Vector2i move( int _dx, int _dy, float _simulationDuration,
			int _environmentWidth, int _environmentHeight )
	{
		Vector2i realMotion = new Vector2i( _dx, _dy );
		
		// Compute the new expected position
		int newX = this.position.x + _dx;
		int newY = this.position.y + _dy;

		// Check if the new position is not outside environment bounds
		if ( newX < 0 )
		{
			realMotion.setX( -this.position.x );
			newX = 0;
		}
		else if ( newX >= _environmentWidth )
		{
			realMotion.setX( _environmentWidth - this.position.x - 1 );
			newX = _environmentWidth - 1;
		}

		if ( newY < 0 )
		{
			realMotion.setY( -this.position.y );
			newY = 0;
		}
		else if ( newY >= _environmentHeight )
		{
			realMotion.setY( _environmentHeight - this.position.y - 1 );
			newY = _environmentHeight - 1;
		}

		this.position.set( newX, newY );

		return realMotion;
	}
}
